import hashlib
import time
from copy import deepcopy

from app.settings import BASE_DIR
from utils import write_file, read_from_file, write_to_yaml, read_from_yaml, clean_path

# todo 这里项目运行会读写文件作为模板，数据结构层面不允许修改模板
apiserver_service_module = read_from_file("{}/deploy/module/kubernetes/kube-apiserver.service".format(BASE_DIR))
audit_config_module = read_from_file("{}/deploy/module/kubernetes/audit.yaml".format(BASE_DIR))
scheduler_service_module = read_from_file("{}/deploy/module/kubernetes/kube-scheduler.service".format(BASE_DIR))
controller_manager_service_module = read_from_file(
    "{}/deploy/module/kubernetes/kube-controller-manager.service".format(BASE_DIR)
)
kubelet_service_module = read_from_file("{}/deploy/module/kubernetes/kubelet.service".format(BASE_DIR))
kubelet_config_module = read_from_yaml("{}/deploy/module/kubernetes/kubelet-config.yaml".format(BASE_DIR))
kube_proxy_service_module = read_from_file("{}/deploy/module/kubernetes/kube-proxy.service".format(BASE_DIR))

APISERVER_SERVICE_NAME = "kube-apiserver.service"
SCHEDULER_SERVICE_PATH = "kube-scheduler.service"
CONTROLLER_MANAGER_SERVICE_NAME = "kube-controller-manager.service"
KUBELET_SERVICE_NAME = "kubelet.service"
KUBELET_CONFIG_NAME = "kubelet-config.yaml"
TOKEN_NAME = "token.csv"
AUDIT_CONFIG_NAME = "audit-policy.yaml"
KUBE_PROXY_SERVICE_NAME = "kube-proxy.service"

K8S_CA_NAME = "k8s-ca.pem"  # 用来验证访问apiserver的客户端证书的ca
K8S_CA_KEY_NAME = "k8s-ca-key.pem"  # 与ca证书一起使用可以签署新的客户端或者服务端证书
SERVER_CERT_NAME = "apiserver-cert.pem"  # apiserver的服务端证书
SERVER_KEY_NAME = "apiserver-key.pem"  # apiserver的服务端私钥

APISERVER_TO_KUBELET_USER = "apiserver-to-kubelet"  # apiserver访问kubelet使用的用户名
APISERVER_TO_KUBELET_CLIENT_CERT_NAME = "apiserver-to-kubelet-client-cert.pem"  # apiserver访问kubelet的客户端证书
APISERVER_TO_KUBELET_CLIENT_KEY_NAME = "apiserver-to-kubelet-client-key.pem"  # apiserver访问kubelet的客户端私钥

SA_CERT_NAME = "sa-cert.pem"  # 对sa签发token的证书
SA_KEY_NAME = "sa-key.pem"  # 对sa签发token的私钥

PROXY_CA_NAME = "k8s-proxy-ca.pem"  # apiserver用来验证扩展API、被代理服务的服务端证书的ca?
PROXY_CLIENT_CERT_NAME = "proxy-client-cert.pem"  # apiserver作为代理访问扩展API的客户端证书
PROXY_CLIENT_KEY_NAME = "proxy-client-key.pem"  # apiserver作为代理访问扩展API的客户端私钥

ETCD_CA_NAME = "etcd-ca.pem"  # apiserver用来验证etcd服务端证书的ca
ETCD_CLIENT_CERT_NAME = "apiserver-to-etcd-client-cert.pem"  # apiserver访问etcd的客户端证书
ETCD_CLIENT_KEY_NAME = "apiserver-to-etcd-client-key.pem"  # apiserver访问etcd的客户端私钥

KUBECONFIG_ADMIN = "admin.kubeconfig"
KUBECONFIG_SCHEDULER = "kube-scheduler.kubeconfig"
KUBECONFIG_CONTROLLER_MANAGER = "kube-controller-manager.kubeconfig"
KUBECONFIG_KUBELET = "kubelet.kubeconfig"
KUBECONFIG_BOOTSTRAP_KUBELET = "bootstrap-kubelet.kubeconfig"
KUBECONFIG_PROXY = "kube-proxy.kubeconfig"

BOOTSTRAP_USER = "kubelet-bootstrap"
BOOTSTRAP_GROUP = "system:node-bootstrapper"


def gen_token_file(out_dir):
    token = hashlib.md5(str(time.time()).encode()).hexdigest()
    content = "{token},{user},10001,\"{group}\"".format(token=token, user=BOOTSTRAP_USER, group=BOOTSTRAP_GROUP)

    path = clean_path(out_dir + "/" + TOKEN_NAME)
    write_file(path, content)
    return path, token


def gen_audit_config(out_dir):
    audit_config = deepcopy(audit_config_module)
    path = clean_path(out_dir + "/" + AUDIT_CONFIG_NAME)
    write_file(path, audit_config)
    return path


def gen_apiserver_service(out_dir, k8s_version, cert_dir, config_dir, audit_dir, etcd_clusters,
                          service_cluster_ip_range,service_node_port_range):
    apiserver_service = deepcopy(apiserver_service_module)

    apiserver_service = apiserver_service.format(**{
        "service_cluster_ip_range": service_cluster_ip_range,
        "service_node_port_range": service_node_port_range,
        "token_path": clean_path(config_dir + "/" + TOKEN_NAME),
        "etcd_ca_path": clean_path(cert_dir + "/" + ETCD_CA_NAME),
        "etcd_client_cert_path": clean_path(cert_dir + "/" + ETCD_CLIENT_CERT_NAME),
        "etcd_client_key_path": clean_path(cert_dir + "/" + ETCD_CLIENT_KEY_NAME),
        "etcd_cluster": ",".join(etcd_clusters),
        "k8s_ca_path": clean_path(cert_dir + "/" + K8S_CA_NAME),
        "server_cert_path": clean_path(cert_dir + "/" + SERVER_CERT_NAME),
        "server_key_path": clean_path(cert_dir + "/" + SERVER_KEY_NAME),
        "kubelet_client_cert_path": clean_path(cert_dir + "/" + APISERVER_TO_KUBELET_CLIENT_CERT_NAME),
        "kubelet_client_key_path": clean_path(cert_dir + "/" + APISERVER_TO_KUBELET_CLIENT_KEY_NAME),
        "proxy_ca_path": clean_path(cert_dir + "/" + PROXY_CA_NAME),
        "proxy_client_cert_path": clean_path(cert_dir + "/" + PROXY_CLIENT_CERT_NAME),
        "proxy_client_key_path": clean_path(cert_dir + "/" + PROXY_CLIENT_KEY_NAME),
        "sa_cert_path": clean_path(cert_dir + "/" + SA_CERT_NAME),
        "sa_key_path": clean_path(cert_dir + "/" + SA_KEY_NAME),
        "audit_log_path": clean_path(audit_dir + "/" + "audit.log"),
        "audit_yaml_path": clean_path(config_dir + "/" + AUDIT_CONFIG_NAME),
        "feature_gates": "ServiceAppProtocol=true" if k8s_version == "1.18" else "",
    })

    path = clean_path(out_dir + "/" + APISERVER_SERVICE_NAME)
    write_file(path, apiserver_service)
    return path


def gen_scheduler_service(out_dir, config_dir):
    scheduler_service = deepcopy(scheduler_service_module)

    scheduler_service = scheduler_service.format(
        kubeconfig_path=clean_path(config_dir + "/" + KUBECONFIG_SCHEDULER),
    )

    path = clean_path(out_dir + "/" + SCHEDULER_SERVICE_PATH)
    write_file(path, scheduler_service)
    return path


def gen_controller_manager_service(out_dir, cert_dir, config_dir, service_cluster_ip_range, cluster_cidr):
    controller_service = deepcopy(controller_manager_service_module)

    controller_service = controller_service.format(
        cluster_cidr=cluster_cidr,
        service_cluster_ip_range=service_cluster_ip_range,
        kubeconfig_path=clean_path(config_dir + "/" + KUBECONFIG_CONTROLLER_MANAGER),
        root_ca_path=clean_path(cert_dir + "/" + K8S_CA_NAME),
        cluster_signing_ca_path=clean_path(cert_dir + "/" + K8S_CA_NAME),
        cluster_signing_key_path=clean_path(cert_dir + "/" + K8S_CA_KEY_NAME),
        sa_key_path=clean_path(cert_dir + "/" + SA_KEY_NAME),
        proxy_ca_path=clean_path(cert_dir + "/" + PROXY_CA_NAME),
    )

    path = clean_path(out_dir + "/" + CONTROLLER_MANAGER_SERVICE_NAME)
    write_file(path, controller_service)
    return path


def gen_kubelet_service_map(out_dir, cert_dir, config_dir, work_dir, ip_list, pod_infra_container_image):
    result = {}
    for ip in ip_list:
        kubelet_service = deepcopy(kubelet_service_module)

        kubelet_service = kubelet_service.format(
            config_path=clean_path(config_dir + "/" + KUBELET_CONFIG_NAME),
            kubeconfig=clean_path(config_dir + "/" + KUBECONFIG_KUBELET),
            bootstrap_kubeconfig=clean_path(config_dir + "/" + KUBECONFIG_BOOTSTRAP_KUBELET),
            pod_infra_container_image=pod_infra_container_image,
            root_dir=clean_path(work_dir + "/kubelet"),
            cert_dir=cert_dir,
            node_ip=str(ip),
        )

        path = clean_path(out_dir + "/{}/".format(ip) + KUBELET_SERVICE_NAME)
        write_file(path, kubelet_service)
        result[ip] = path

    return result


def gen_kubelet_config_map(out_dir, cert_dir, ip_list, cluster_dns_list):
    result = {}
    for ip in ip_list:
        kubelet_config = deepcopy(kubelet_config_module)
        kubelet_config["authentication"]["x509"]["clientCAFile"] = clean_path(cert_dir + "/" + K8S_CA_NAME)
        kubelet_config["clusterDNS"] = cluster_dns_list
        kubelet_config["address"] = str(ip)

        path = clean_path(out_dir + "/{}/".format(ip) + KUBELET_CONFIG_NAME)
        write_to_yaml(path, kubelet_config)
        result[ip] = path
    return result


def gen_kube_proxy_service_map(out_dir, config_dir, ip_list, cluster_cidr):
    result = {}
    for ip in ip_list:
        kube_proxy_service = deepcopy(kube_proxy_service_module)

        kube_proxy_service = kube_proxy_service.format(
            kubeconfig=clean_path(config_dir + "/" + KUBECONFIG_PROXY),
            node_ip=str(ip),
            cluster_cidr=cluster_cidr,
        )

        path = clean_path(out_dir + "/{}/".format(ip) + KUBE_PROXY_SERVICE_NAME)
        write_file(path, kube_proxy_service)
        result[ip] = path

    return result
